#pragma once
#include<string.h>
#include<stdlib.h>
#include<iostream>
#include<string>

#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<fcntl.h>

typedef struct sockaddr sockadr;
typedef struct sockaddr_in sockaddr_in;

class TcpSocket
{
	private:
		int fd_;
	public:
		TcpSocket():fd_(-1){}
		TcpSocket(int fd):fd_(fd){}

		bool Socket()
		{
			fd_ = socket(AF_INET,SOCK_STREAM,0);
			
			std::cout<<"open fd = "<<fd_<<std::endl;
			return true;
		}
		bool Close()
		{
			close(fd_);
			std::cout<<"close fd = "<<fd_<<std::endl;
			return true;
		}
		bool Bind(const std::string& ip, uint16_t port)
		{
			sockaddr_in addr;
			addr.sin_family = AF_INET;
			addr.sin_addr.s_addr = inet_addr(ip.c_str());
			addr.sin_port = htons(port);

			int ret = bind(fd_,(sockaddr*)&addr,sizeof(addr));
			std::cout<<"bind fd: "<<ret<<std::endl;
			return true;
		}
		bool Listen(int num)
		{
			int ret = listen(fd_,num);
			
			return true;
		}
		bool Accept(TcpSocket* dest,std::string* ip = NULL, uint16_t* port = NULL)
		{
			sockaddr_in dest_addr;
			socklen_t len = sizeof(dest_addr);
			int new_sock = accept(fd_,(sockaddr*)&dest_addr,&len);

			std::cout<<"accept fd: "<<new_sock<<std::endl;
			dest->fd_ = new_sock;
			if(ip != NULL)
			{
				*ip = inet_ntoa(dest_addr.sin_addr);
			}
			if(port != NULL)
			{
				*port = ntohs(dest_addr.sin_port);
			}
			return true;
		}
		bool Recv(std::string* buf)
		{
			buf->clear();
			char tmp[1024] = {0};
			ssize_t read_size = recv(fd_,tmp,sizeof(tmp),0);
			buf->assign(tmp);
			return true;
		}
		bool Send(const std::string& buf)
		{
			ssize_t write_size = send(fd_,buf.data(),buf.size(),0);
			return true;
		}
		bool Connect(const std::string& ip,uint16_t port)
		{
			sockaddr_in addr;
			addr.sin_family = AF_INET;
			addr.sin_addr.s_addr = inet_addr(ip.c_str());
			addr.sin_port = htons(port);
			int ret = connect(fd_,(sockaddr*)&addr,sizeof(addr));
			return true;
		}
		int GetFd()
		{
			return fd_;
		}
};

